package web

import (
	"errors"
	"net/http"
	"net/url"
	"reflect"
	"strconv"
	"strings"
	"time"
)

// RequestQuery 查询
type RequestQuery struct {
	request    *http.Request
	queryCache url.Values
}

func NewRequestQuery(req *http.Request) *RequestQuery {
	r := &RequestQuery{
		request:    req,
		queryCache: req.URL.Query(),
	}
	return r
}

func (q *RequestQuery) queryArray(key string) (values []string, ok bool) {
	values, ok = q.queryCache[key]
	return
}

func (q *RequestQuery) DefaultQuery(key string, value string) {
	q.queryCache.Set(key, value)
}

func (q *RequestQuery) QueryString(key string) (value string, err error) {
	var (
		values []string
		ok     bool
	)
	if values, ok = q.queryArray(key); !ok {
		return "", errors.New("查询的Key[" + key + "]不存在")
	}
	value = values[0]
	return
}

func (q *RequestQuery) QueryInt(key string) (value int, err error) {
	query, err := q.QueryString(key)
	if err != nil {
		return 0, err
	}
	value, err = strconv.Atoi(query)
	return
}

func (q *RequestQuery) QueryInt8(key string) (value int8, err error) {
	var (
		query  string
		target int64
	)
	if query, err = q.QueryString(key); err != nil {
		return 0, err
	}
	if target, err = strconv.ParseInt(query, 10, 8); err != nil {
		return 0, err
	}
	value = int8(target)
	return
}

func (q *RequestQuery) QueryInt16(key string) (value int16, err error) {
	var (
		query  string
		target int64
	)
	if query, err = q.QueryString(key); err != nil {
		return 0, err
	}
	if target, err = strconv.ParseInt(query, 10, 16); err != nil {
		return 0, err
	}
	value = int16(target)
	return
}

func (q *RequestQuery) QueryInt32(key string) (value int32, err error) {
	var (
		query  string
		target int64
	)
	if query, err = q.QueryString(key); err != nil {
		return 0, err
	}
	if target, err = strconv.ParseInt(query, 10, 32); err != nil {
		return 0, err
	}
	value = int32(target)
	return
}

func (q *RequestQuery) QueryInt64(key string) (value int64, err error) {
	var (
		query string
	)
	if query, err = q.QueryString(key); err != nil {
		return 0, err
	}
	value, err = strconv.ParseInt(query, 10, 64)
	return
}

func (q *RequestQuery) QueryFloat32(key string) (value float32, err error) {
	var (
		query  string
		target float64
	)
	if query, err = q.QueryString(key); err != nil {
		return 0, err
	}
	if target, err = strconv.ParseFloat(query, 32); err != nil {
		return 0, err
	}
	value = float32(target)
	return
}

func (q *RequestQuery) QueryFloat64(key string) (value float64, err error) {
	var (
		query string
	)
	if query, err = q.QueryString(key); err != nil {
		return 0, err
	}
	value, err = strconv.ParseFloat(query, 64)
	return
}

func (q *RequestQuery) QueryBool(key string) (value bool, err error) {
	var (
		query string
	)
	if query, err = q.QueryString(key); err != nil {
		return false, err
	}
	if query == "1" || query == "true" || query == "True" {
		return true, nil
	}
	if query == "0" || query == "false" || query == "False" {
		return false, nil
	}
	return false, errors.New("转为Bool类型失败")
}

func (q *RequestQuery) QueryTime(key string) (value time.Time, err error) {
	//TODO implement me
	panic("implement me")
}

// QueryJson 将 Query 请求转为 json 对象
func (q *RequestQuery) QueryJson(obj any) error {
	objValue := reflect.ValueOf(obj)
	if objValue.Kind() != reflect.Ptr || objValue.IsNil() {
		return errors.New("obj必须是非零的结构体指针")
	}

	objElem := objValue.Elem()

	for i := 0; i < objElem.NumField(); i++ {

		fieldType := objElem.Type()
		field := fieldType.Field(i)
		tag := field.Tag
		name := tag.Get("json")

		if name == "" {
			name = strings.ToLower(field.Name)
		}

		fieldValue := objElem.Field(i)

		switch fieldValue.Kind() {
		case reflect.Int:
			value, err := q.QueryInt(name)
			if err != nil {
				continue
			}
			fieldValue.Set(reflect.ValueOf(value))
		case reflect.Int8:
			value, err := q.QueryInt8(name)
			if err != nil {
				continue
			}
			fieldValue.Set(reflect.ValueOf(value))
		case reflect.Int16:
			value, err := q.QueryInt16(name)
			if err != nil {
				continue
			}
			fieldValue.Set(reflect.ValueOf(value))
		case reflect.Int32:
			value, err := q.QueryInt32(name)
			if err != nil {
				continue
			}
			fieldValue.Set(reflect.ValueOf(value))
		case reflect.Int64:
			value, err := q.QueryInt64(name)
			if err != nil {
				continue
			}
			fieldValue.Set(reflect.ValueOf(value))
		case reflect.Float32:
			value, err := q.QueryFloat32(name)
			if err != nil {
				continue
			}
			fieldValue.Set(reflect.ValueOf(value))
		case reflect.Float64:
			value, err := q.QueryFloat64(name)
			if err != nil {
				continue
			}
			fieldValue.Set(reflect.ValueOf(value))
		case reflect.Bool:
			value, err := q.QueryBool(name)
			if err != nil {
				continue
			}
			fieldValue.Set(reflect.ValueOf(value))
		case reflect.Slice:
			value, ok := q.queryArray(name)
			if !ok {
				continue
			}
			fieldValue.Set(reflect.ValueOf(value))
		case reflect.String:
			fieldValue.Set(reflect.ValueOf(q.queryCache.Get(name)))
		default:
			// 处理其他类型的字段，如果需要
		}
	}
	return nil
}
